<?php

namespace App\Http\Controllers;

use App\Models\Dorm;
use App\Models\Staff;
use App\Models\StaffDormAdjust;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Prettus\Validator\Contracts\ValidatorInterface;
use Prettus\Validator\Exceptions\ValidatorException;
use App\Http\Requests\StaffDormAdjustCreateRequest;
use App\Http\Requests\StaffDormAdjustUpdateRequest;
use App\Repositories\StaffDormAdjustRepository;
use App\Validators\StaffDormAdjustValidator;

/**
 * Class StaffDormAdjustsController.
 *
 * @package namespace App\Http\Controllers;
 */
class StaffDormAdjustsController extends Controller
{
    /**
     * @var StaffDormAdjustRepository
     */
    protected $repository;

    /**
     * @var StaffDormAdjustValidator
     */
    protected $validator;

    /**
     * StaffDormAdjustsController constructor.
     *
     * @param StaffDormAdjustRepository $repository
     * @param StaffDormAdjustValidator $validator
     */
    public function __construct(StaffDormAdjustRepository $repository, StaffDormAdjustValidator $validator)
    {
        $this->repository = $repository;
        $this->validator = $validator;
    }

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $this->repository->pushCriteria(app('Prettus\Repository\Criteria\RequestCriteria'));
        //        $this->repository->setPresenter(StaffDormAdjustPresenter::class);
        $staffDormAdjusts = $this->repository->with(['company', 'staff:id,name,sex,id_card,card_num', 'dormFrom:id,code', 'dormTo:id,code'])->paginate(\request()->get('limit', 20));

        if (request()->wantsJson()) {

            return response()->json([
                'data' => $staffDormAdjusts,
            ]);
        }

        return view('staffDormAdjusts.index', compact('staffDormAdjusts'));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  StaffDormAdjustCreateRequest $request
     *
     * @return \Illuminate\Http\Response
     *
     * @throws \Prettus\Validator\Exceptions\ValidatorException
     */
    public function store(StaffDormAdjustCreateRequest $request)
    {
        try {
            $this->validator->with($request->all())->passesOrFail(ValidatorInterface::RULE_CREATE);
            try {
                $staffId = $request->get('staff_id');
                $staff = Staff::find($staffId);
                if ($staff->dorm_id == null && request()->get('dorm_id_from')) {
                    $msg = "当前员工没有入住宿舍，不能进行搬出或换房操作";
                    throw new \Exception($msg);
                }

                $latestAdjust = $this->repository->findLatestAdjust($staffId);
                $adjustDate = $request->get('adjust_date');
                if ($latestAdjust && $adjustDate < $latestAdjust->adjust_date) {
                    $msg = "新的调整日期必须要大于或等于上一次调整日期 $latestAdjust->adjust_date";
                    throw new \Exception($msg);
                }

                $founds = $this->repository->findWhere($request->only(['staff_id', 'dorm_id_from', 'dorm_id_to', 'adjust_date']));

                //避免重复创建
                if ($founds->count() == 0) {
                    DB::beginTransaction();
                    //记录本次调整
                    $dormCodeTo = $request->get('dorm_code_to');
                    if ($dormCodeTo) {
                        //校验入住宿舍号是否有误，因为安排宿舍的时候是可以人为输入宿舍号的。
                        $dormTo = Dorm::where('code', $dormCodeTo)->first();
                        if ($dormTo) {
                            $staff = Staff::find($staffId);
                            $staff->dorm_id = optional($dormTo)->id;
                            $staff->latest_in_date = $request->get('adjust_date');
                            $staff->save();
                            $request->merge(['dorm_id_to' => $dormTo->id]);
                        } else {
                            //找不到，入住宿舍为空，相当与搬出
                            $msg = "没有找到宿舍'$dormCodeTo',请输入正确的宿舍号";
                            throw new \Exception($msg);
                        }
                    } else {
                        //没有提供入住宿舍
                        $staff = Staff::find($staffId);
                        $staff->dorm_id = null;
                        $staff->latest_in_date = null;
                        $staff->save();
                    }
                    $staffDormAdjust = $this->repository->create($request->all());
                    DB::commit();
                } else {
                    $msg = "重复的调整信息";
                    throw new \Exception($msg);
                }

                $response = [
                    'message' => 'StaffDormAdjust created.',
                    'data' => $staffDormAdjust->toArray(),
                ];
                if ($request->wantsJson()) {
                    return response()->json($response);
                }
                return redirect()->back()->with('message', $response['message']);
            } catch (\Exception $exception) {
                DB::rollBack();
                if ($request->wantsJson()) {
                    return response()->json([
                        'error' => true,
                        'message' => $exception->getMessage()
                    ]);
                }
                return redirect()->back()->withErrors($exception->getMessage());
            }
        } catch (ValidatorException $e) {
            if ($request->wantsJson()) {
                return response()->json([
                    'error' => true,
                    'message' => $e->getMessageBag()
                ]);
            }

            return redirect()->back()->withErrors($e->getMessageBag())->withInput();
        }
    }

    /**
     * Display the specified resource.
     *
     * @param  int $id
     *
     * @return \Illuminate\Http\Response
     */
    public
    function show($id)
    {
        $staffDormAdjust = $this->repository->find($id);

        if (request()->wantsJson()) {

            return response()->json([
                'data' => $staffDormAdjust,
            ]);
        }

        return view('staffDormAdjusts.show', compact('staffDormAdjust'));
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int $id
     *
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $staffDormAdjust = $this->repository->find($id);

        return view('staffDormAdjusts.edit', compact('staffDormAdjust'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  StaffDormAdjustUpdateRequest $request
     * @param  string $id
     *
     * @return Response
     *
     * @throws \Prettus\Validator\Exceptions\ValidatorException
     */
    public function update(StaffDormAdjustUpdateRequest $request, $id)
    {
        try {

            $this->validator->with($request->all())->passesOrFail(ValidatorInterface::RULE_UPDATE);
            $staffAdjusts = $this->repository->findWhere(['staff_id' => $request->get('staff_id')]);
            $index = $staffAdjusts->search(function ($item) use ($id) {
                return $item->id == $id;
            });
            $adjustDate = $request->get('adjust_date');
            $cur = $staffAdjusts[$index];
            $prev = $index > 0 ? $staffAdjusts[$index - 1] : null;
            $next = $index < $staffAdjusts->count() - 1 ? $staffAdjusts[$index + 1] : null;
            $meet = false;
            if ($prev && $next) {
                //调整日期在上次调整和下次调整之间
                if ($adjustDate >= $prev->adjust_date && $adjustDate <= $next->adjust_date) {
                    $meet = true;
                }
            } else {
                //之前还有一个调整，那么本次调整的日期必须在前次调整之后
                if ($prev && $adjustDate >= $prev->adjust_date) {
                    $meet = true;
                }
                //之后还有一次调整，那么本次调整必须在该调整之前
                if ($next && $adjustDate <= $next->adjust_date) {
                    $meet = true;
                }
                //本次调整为第一条录入的调整
                if (!$prev && !$next) {
                    $meet = true;
                }
            }
            if ($meet) {
                try {
                    DB::beginTransaction();
                    $staffDormAdjust = $this->repository->update($request->all(), $id);
                    //更新
                    if ($cur->adjust_type != 'out') {
                        Staff::query()->find($cur->staff_id)->update(['latest_in_date' => $adjustDate]);
                    } else {
                        // dd($cur->adjust_type);
                    }
                    $response = [
                        'message' => 'StaffDormAdjust updated.',
                        'data' => $staffDormAdjust->toArray(),
                    ];
                    DB::commit();

                    if ($request->wantsJson()) {
                        return response()->json($response);
                    }

                    return redirect()->back()->with('message', $response['message']);
                } catch (\Exception $ex) {
                    if ($request->wantsJson()) {
                        return response()->json([
                            'error' => true,
                            'message' => $ex->getMessage()
                        ]);
                    }
                    return redirect()->back()->withErrors($ex->getMessage())->withInput();
                }
            } else {
                $prevDate = optional($prev)->adjust_date;
                $nextDate = optional($next)->adjust_date;
                $msg = "更新的调整时间必须符合：'$prevDate'<=调整时间<='$nextDate'，$adjustDate 不在此范围！";
                if ($request->wantsJson()) {
                    return response()->json([
                        'error' => true,
                        'message' => $msg
                    ]);
                }
                return redirect()->back()->withErrors($msg)->withInput();
            }
        } catch (ValidatorException $e) {

            if ($request->wantsJson()) {

                return response()->json([
                    'error' => true,
                    'message' => $e->getMessageBag()
                ]);
            }

            return redirect()->back()->withErrors($e->getMessageBag())->withInput();
        }
    }


    /**
     * Remove the specified resource from storage.
     *
     * @param  int $id
     *
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        try {
            $adjust = $this->repository->find($id);
            $hasNewerAdjust = StaffDormAdjust::query()
                ->where([['staff_id', $adjust->staff_id], ['adjust_date', '>=', $adjust->adjust_date], ['created_at', '>', $adjust->created_at]])
                ->exists();
            if ($hasNewerAdjust) {
                $msg = "存在比此调整更新的调整，必须从最新的调整开始删除！";
                throw new \Exception($msg);
            }

            DB::beginTransaction();
            if ($adjust->adjust_type == 'in') {
                //删除的入住记录，员工恢复为无入住状态，需将已经分配的宿舍释放
                $adjust->staff->update(['dorm_id' => null, 'latest_in_date' => null]);
            } else {
                //将之前分配的宿舍还原
                $prevAdjust = StaffDormAdjust::query()
                    ->where([['staff_id', $adjust->staff_id], ['adjust_date', '<=', $adjust->adjust_date], ['created_at', '<', $adjust->created_at]])
                    ->orderBy('adjust_date', 'desc')->orderBy('created_at', 'desc')
                    ->first();
                $adjust->staff->update(['dorm_id' => $adjust->dorm_id_from, 'latest_in_date' => $prevAdjust->adjust_date]);
            }
            $deleted = $this->repository->delete($id);
            DB::commit();
            if (request()->wantsJson()) {

                return response()->json([
                    'message' => 'StaffDormAdjust deleted.',
                    'deleted' => $deleted,
                ]);
            }

            return redirect()->back()->with('message', 'StaffDormAdjust deleted.');
        } catch (Exception $ex) {
            if (request()->wantsJson()) {
                return response()->json([
                    'deleted' => false,
                    'message' => $ex->getMessage(),
                ]);
            } else {
                return redirect()->back()->withErrors($ex->getMessage());
            }
        }
    }
}
